﻿using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace GameX.GameContent
{
    class TilesSpriteSheet : ISpriteSheet
    {
        private const int ORDINARY_TILE_WIDTH = 64;
        private const int ORDINARY_TILE_HEIGHT = 64;

        private const int FIR1_TILE_INDEX = 97;
        private const int FIR2_TILE_INDEX = 98;
        private const int FIR_TILE_WIDTH = ORDINARY_TILE_WIDTH;
        private const int FIR_TILE_HEIGHT = ORDINARY_TILE_HEIGHT * 2;

        private const int TREE1_LEAVES_TILE_INDEX = 105;
        private const int TREE1_NO_LEAVES_TILE_INDEX = 106;
        private const int TREE1_TILE_WIDTH = ORDINARY_TILE_WIDTH;
        private const int TREE1_TILE_HEIGHT = ORDINARY_TILE_HEIGHT * 3;

        private const int TREE2_LEAVES_TILE_INDEX = 107;
        private const int TREE2_NO_LEAVES_TILE_INDEX = 108;
        private const int TREE2_TILE_WIDTH = ORDINARY_TILE_WIDTH;
        private const int TREE2_TILE_HEIGHT = ORDINARY_TILE_HEIGHT * 2;

        private const int TREE3_LEAVES_TILE_INDEX = 109;
        private const int TREE3_NO_LEAVES_TILE_INDEX = 110;
        private const int TREE3_NO_LEAVES_TILE_WIDTH = ORDINARY_TILE_WIDTH * 3;
        private const int TREE3_NO_LEAVES_TILE_HEIGHT = ORDINARY_TILE_HEIGHT * 2;
        private const int TREE3_LEAVES_TILE_WIDTH = ORDINARY_TILE_WIDTH * 3;
        private const int TREE3_LEAVES_TILE_HEIGHT = ORDINARY_TILE_HEIGHT * 3;

        private Texture2D m_tilesSpriteSheet;

        private int[][] m_itemCoordinates = new int[][]
        {
        new int[] { 0, 0 },
        new int[] { 64, 0 },
        new int[] { 128, 0 },
        new int[] { 192, 0 },
        new int[] { 256, 0 },
        new int[] { 320, 0 },
        new int[] { 384, 0 },

        new int[] { 0, 64 },
        new int[] { 64, 64 },
        new int[] { 128, 64 },
        new int[] { 192, 64 },
        new int[] { 256, 64 },
        new int[] { 320, 64 },
        new int[] { 384, 64 },
        new int[] { 448, 64 },

        new int[] { 0, 128 },
        new int[] { 64, 128 },
        new int[] { 128, 128 },
        new int[] { 192, 128 },

        new int[] { 0, 192 },
        new int[] { 64, 192 },
        new int[] { 128, 192 },
        new int[] { 192, 192 },
        new int[] { 256, 192 },
        new int[] { 320, 192 },
        new int[] { 384, 192 },
        new int[] { 448, 192 },
        new int[] { 512, 192 },

        new int[] { 0, 256 },
        new int[] { 64, 256 },
        new int[] { 128, 256 },
        new int[] { 192, 256 },

        new int[] { 0, 320 },
        new int[] { 64, 320 },
        new int[] { 128, 320 },
        new int[] { 192, 320 },
        new int[] { 256, 320 },
        new int[] { 320, 320 },
        new int[] { 384, 320 },
        new int[] { 448, 320 },
        new int[] { 512, 320 },
        new int[] { 576, 320 },

        new int[] { 0, 384 },
        new int[] { 64, 384 },
        new int[] { 128, 384 },
        new int[] { 192, 384 },
        new int[] { 256, 384 },
        new int[] { 320, 384 },
        new int[] { 384, 384 },
        new int[] { 448, 384 },
        new int[] { 512, 384 },
        new int[] { 576, 384 },

        new int[] { 0, 448 },
        new int[] { 64, 448 },
        new int[] { 128, 448 },
        new int[] { 192, 448 },
        new int[] { 256, 448 },
        new int[] { 320, 448 },
        new int[] { 384, 448 },
        new int[] { 448, 448 },
        new int[] { 512, 448 },
        new int[] { 576, 448 },

        new int[] { 0, 512 },
        new int[] { 64, 512 },
        new int[] { 128, 512 },
        new int[] { 192, 512 },
        new int[] { 256, 512 },
        new int[] { 320, 512 },
        new int[] { 384, 512 },
        new int[] { 448, 512 },
        new int[] { 512, 512 },
        new int[] { 576, 512 },

        new int[] { 0, 576 },
        new int[] { 64, 576 },
        new int[] { 128, 576 },
        new int[] { 192, 576 },
        new int[] { 256, 576 },
        new int[] { 320, 576 },
        new int[] { 384, 576 },
        new int[] { 448, 576 },
        new int[] { 512, 576 },
        new int[] { 576, 576 },

        new int[] { 0, 640 },
        new int[] { 64, 640 },
        new int[] { 128, 640 },

        new int[] { 0, 704 },
        new int[] { 64, 704 },
        new int[] { 128, 704 },
        new int[] { 192, 704 },
        new int[] { 256, 704 },
        new int[] { 320, 704 },
        new int[] { 384, 704 },
        new int[] { 448, 704 },
        new int[] { 512, 704 },
        new int[] { 576, 704 },

        new int[] { 0, 768 },
        new int[] { 64, 768 },
        new int[] { 128, 768 },
        new int[] { 192, 768 },
        new int[] { 256, 768 },
        new int[] { 320, 768 },
        new int[] { 384, 768 },
        new int[] { 448, 768 },
        new int[] { 512, 768 },
        new int[] { 576, 768 },

        new int[] { 0, 832 },
        new int[] { 64, 832 },
        new int[] { 448, 832 },

        new int[] { 128, 896 },
        new int[] { 192, 896 },
        new int[] { 256, 896 }
        };

        public TilesSpriteSheet(ContentManager contentManager)
        {
            if (contentManager == null)
            {
                throw new ArgumentNullException("contentManager");
            }

            // TODO: catch and log ContentLoadException for invalid content (after error logging is implemented).
            m_tilesSpriteSheet = contentManager.Load<Texture2D>("Tiles");
        }

        public Rectangle GetSpriteBounds(uint tile)
        {
            int[] tileCoordinates = m_itemCoordinates[tile];

            switch (tile)
            {
                case FIR1_TILE_INDEX:
                case FIR2_TILE_INDEX:
                    return new Rectangle(tileCoordinates[0], tileCoordinates[1], FIR_TILE_WIDTH, FIR_TILE_HEIGHT);
                case TREE1_LEAVES_TILE_INDEX:
                case TREE1_NO_LEAVES_TILE_INDEX:
                    return new Rectangle(tileCoordinates[0], tileCoordinates[1], TREE1_TILE_WIDTH, TREE1_TILE_HEIGHT);
                case TREE2_LEAVES_TILE_INDEX:
                case TREE2_NO_LEAVES_TILE_INDEX:
                    return new Rectangle(tileCoordinates[0], tileCoordinates[1], TREE2_TILE_WIDTH, TREE2_TILE_HEIGHT);
                case TREE3_NO_LEAVES_TILE_INDEX:
                    return new Rectangle(tileCoordinates[0], tileCoordinates[1], TREE3_NO_LEAVES_TILE_WIDTH, TREE3_NO_LEAVES_TILE_HEIGHT);
                case TREE3_LEAVES_TILE_INDEX:
                    return new Rectangle(tileCoordinates[0], tileCoordinates[1], TREE3_LEAVES_TILE_WIDTH, TREE3_LEAVES_TILE_HEIGHT);
                default:
                    return new Rectangle(tileCoordinates[0], tileCoordinates[1], ORDINARY_TILE_WIDTH, ORDINARY_TILE_HEIGHT);
            }
        }


        public Texture2D Texture
        {
            get
            {
                return m_tilesSpriteSheet;
            }
        }


        public int GetTileWidth(uint tile)
        {
            switch (tile)
            {
                case FIR1_TILE_INDEX:
                case FIR2_TILE_INDEX:
                    return FIR_TILE_WIDTH;
                case TREE1_LEAVES_TILE_INDEX:
                case TREE1_NO_LEAVES_TILE_INDEX:
                    return TREE1_TILE_WIDTH;
                case TREE2_LEAVES_TILE_INDEX:
                case TREE2_NO_LEAVES_TILE_INDEX:
                    return TREE2_TILE_WIDTH;
                case TREE3_NO_LEAVES_TILE_INDEX:
                    return TREE3_NO_LEAVES_TILE_WIDTH;
                case TREE3_LEAVES_TILE_INDEX:
                    return TREE3_LEAVES_TILE_WIDTH;
                default:
                    return ORDINARY_TILE_WIDTH;
            }
        }

        public int GetTileHeight(uint tile)
        {
            switch (tile)
            {
                case FIR1_TILE_INDEX:
                case FIR2_TILE_INDEX:
                    return FIR_TILE_HEIGHT;
                case TREE1_LEAVES_TILE_INDEX:
                case TREE1_NO_LEAVES_TILE_INDEX:
                    return TREE1_TILE_HEIGHT;
                case TREE2_LEAVES_TILE_INDEX:
                case TREE2_NO_LEAVES_TILE_INDEX:
                    return TREE2_TILE_HEIGHT;
                case TREE3_NO_LEAVES_TILE_INDEX:
                    return TREE3_NO_LEAVES_TILE_HEIGHT;
                case TREE3_LEAVES_TILE_INDEX:
                    return TREE3_LEAVES_TILE_HEIGHT;
                default:
                    return ORDINARY_TILE_HEIGHT;
            }
        }

        public Rectangle GetTileBase(uint tile)
        {
            int[] tileCoordinates = m_itemCoordinates[tile];

            int baseXPoint;
            int baseYPoint;

            switch (tile)
            {
                case FIR1_TILE_INDEX:
                case FIR2_TILE_INDEX:
                    baseXPoint = tileCoordinates[0];
                    baseYPoint = tileCoordinates[1] + ORDINARY_TILE_HEIGHT;
                    break;
                case TREE1_LEAVES_TILE_INDEX:
                case TREE1_NO_LEAVES_TILE_INDEX:
                    baseXPoint = tileCoordinates[0];
                    baseYPoint = tileCoordinates[1] + 2 * ORDINARY_TILE_HEIGHT;
                    break;
                case TREE2_LEAVES_TILE_INDEX:
                case TREE2_NO_LEAVES_TILE_INDEX:
                    baseXPoint = tileCoordinates[0];
                    baseYPoint = tileCoordinates[1] + ORDINARY_TILE_HEIGHT;
                    break;
                case TREE3_NO_LEAVES_TILE_INDEX:
                    baseXPoint = tileCoordinates[0] + 2 * ORDINARY_TILE_WIDTH;
                    baseYPoint = tileCoordinates[1] + 2 * ORDINARY_TILE_HEIGHT;
                    break;
                case TREE3_LEAVES_TILE_INDEX:
                    baseXPoint = tileCoordinates[0] + 2 * ORDINARY_TILE_WIDTH;
                    baseYPoint = tileCoordinates[1] + 2 * ORDINARY_TILE_HEIGHT;
                    break;
                default:
                    baseXPoint = tileCoordinates[0];
                    baseYPoint = tileCoordinates[1];
                    break;
            }

            return new Rectangle(baseXPoint, baseYPoint, ORDINARY_TILE_WIDTH, ORDINARY_TILE_HEIGHT);
        }
    }
}
